package com.jinzecloud.reportapproval.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.deepoove.poi.config.Configure;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.jinzecloud.reportapproval.bean.ProductSpecificationInfo;
import com.jinzecloud.reportapproval.dto.AdminDto;
import com.jinzecloud.reportapproval.dto.AuditParam;
import com.jinzecloud.reportapproval.dto.DataFromSub;
import com.jinzecloud.reportapproval.dto.DataStagingParam;
import com.jinzecloud.reportapproval.enums.AuditRoleEnums;
import com.jinzecloud.reportapproval.enums.StateEnum;
import com.jinzecloud.reportapproval.enums.TableEnums;
import com.jinzecloud.reportapproval.mapper.AdminMapper;
import com.jinzecloud.reportapproval.service.ProductSpecificationInfoService;
import com.jinzecloud.reportapproval.utils.*;
import com.jinzecloud.reportapproval.vo.ProductSpecificationExportVo;
import com.jinzecloud.reportapproval.vo.ProductSpecificationVo;
import com.jinzecloud.reportapproval.vo.ProductSpecificationVos;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.io.File;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.jinzecloud.reportapproval.mapper.ProductSpecificationMapper;
import com.jinzecloud.reportapproval.bean.ProductSpecification;
import com.jinzecloud.reportapproval.service.ProductSpecificationService;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;


@Service("productSpecificationService")
public class ProductSpecificationServiceImpl extends ServiceImpl<ProductSpecificationMapper, ProductSpecification> implements ProductSpecificationService {

    @Autowired
    private FileUploadUtil fileUploadUtil;
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private ProductSpecificationInfoService productSpecificationInfoService;
    @Autowired
    private ProductSpecificationMapper productSpecificationMapper;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        QueryWrapper<ProductSpecification> productSpecificationQueryWrapper = new QueryWrapper<>();
        productSpecificationQueryWrapper.like("project_number", params.get("key"));
        IPage<ProductSpecification> page = this.page(
                new Query<ProductSpecification>().getPage(params),
                productSpecificationQueryWrapper
        );

        return new PageUtils(page);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R saveProductSpecification(ProductSpecificationVo productSpecificationVo,ProductSpecification productSpecification) throws IllegalAccessException {
        QueryWrapper<ProductSpecification> productSpecificationQueryWrapper = new QueryWrapper<>();
        productSpecificationQueryWrapper.eq("project_number", productSpecificationVo.getProjectNumber());
        List<ProductSpecification> list = this.list(productSpecificationQueryWrapper);
        if (CollectionUtil.isNotEmpty(list)) {
            return R.error("项目编号已存在");
        }
        productSpecification.setProjectNumber(productSpecificationVo.getProjectNumber());
        this.save(productSpecification);

        DataFromSub dataFromSub = productSpecificationVo.getDataFromSub();
        Class<DataFromSub> dataFromSubClass = DataFromSub.class;
        Field[] declaredFields1 = dataFromSubClass.getDeclaredFields();
        for (Field declaredField : declaredFields1) {
            declaredField.setAccessible(true);
            ProductSpecificationInfo productSpecificationInfo = new ProductSpecificationInfo();
            productSpecificationInfo.setCharacteristic(declaredField.getName());
            productSpecificationInfo.setProductSpecificationId(productSpecification.getId());
            productSpecificationInfo.setDesignValue(declaredField.get(dataFromSub));
            productSpecificationInfoService.save(productSpecificationInfo);
        }
        return R.ok();
    }

    @Override
    public ProductSpecificationVo getByProductSpecificationId(Integer id) {
        ProductSpecification productSpecification = this.getById(id);
        ProductSpecificationVo productSpecificationVo = new ProductSpecificationVo();
        BeanUtils.copyProperties(productSpecification, productSpecificationVo);
        QueryWrapper<ProductSpecificationInfo> productSpecificationInfoQueryWrapper = new QueryWrapper<>();
        DataFromSub dataFromSub = new DataFromSub();
        productSpecificationInfoQueryWrapper.eq("product_specification_id", id);
        List<ProductSpecificationInfo> list = productSpecificationInfoService.list(productSpecificationInfoQueryWrapper);
        list.stream().map(productSpecificationInfo -> {
            if (productSpecificationInfo.getCharacteristic().equals("model"))dataFromSub.setModel((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("construction"))dataFromSub.setConstruction((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("outline"))dataFromSub.setOutline((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("job"))dataFromSub.setJob((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("operange"))dataFromSub.setOperange((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("tilldepth"))dataFromSub.setTilldepth((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("cutter"))dataFromSub.setCutter((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("cutterconn"))dataFromSub.setCutterconn((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("drive"))dataFromSub.setDrive((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("transportation"))dataFromSub.setTransportation((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("gearbox"))dataFromSub.setGearbox((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("knife"))dataFromSub.setKnife((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("knifeMax"))dataFromSub.setKnifeMax((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("knifenum"))dataFromSub.setKnifenum((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("tooltype"))dataFromSub.setTooltype((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("depthlimit"))dataFromSub.setDepthlimit((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("suppress"))dataFromSub.setSuppress((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("power"))dataFromSub.setPower((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("rotate"))dataFromSub.setRotate((String)productSpecificationInfo.getDesignValue());
            return null;
        }).collect(Collectors.toList());//.collect(Collectors.toList())
        productSpecificationVo.setDataFromSub(dataFromSub);
        return productSpecificationVo;
    }

    @Override
    public void updateProductSpecificationVoById(ProductSpecificationVo productSpecificationVo) throws IllegalAccessException {
        DataFromSub dataFromSub = productSpecificationVo.getDataFromSub();
        Class<DataFromSub> dataFromSubClass = DataFromSub.class;
        Field[] declaredFields1 = dataFromSubClass.getDeclaredFields();
        for (Field field : declaredFields1) {
            field.setAccessible(true);
            QueryWrapper<ProductSpecificationInfo> productSpecificationInfoQueryWrapper = new QueryWrapper<>();
            productSpecificationInfoQueryWrapper.eq("product_specification_id", productSpecificationVo.getId()).eq("characteristic", field.getName());
            ProductSpecificationInfo productSpecificationInfo = productSpecificationInfoService.getOne(productSpecificationInfoQueryWrapper);
            productSpecificationInfo.setDesignValue(field.get(dataFromSub));
            productSpecificationInfoService.updateById(productSpecificationInfo);
        }
    }

    @Override
    public String getByIdproductInfoExportVo(Integer id) {
        DataFromSub dataFromSub = new DataFromSub();
        ProductSpecification productSpecification = this.getById(id);
        QueryWrapper<ProductSpecificationInfo> productSpecificationInfoQueryWrapper = new QueryWrapper<>();
        productSpecificationInfoQueryWrapper.eq("product_specification_id", id);
        List<ProductSpecificationInfo> list = productSpecificationInfoService.list(productSpecificationInfoQueryWrapper);
        list.stream().map(productSpecificationInfo -> {
            if (productSpecificationInfo.getCharacteristic().equals("model"))dataFromSub.setModel((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("construction"))dataFromSub.setConstruction((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("outline"))dataFromSub.setOutline((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("job"))dataFromSub.setJob((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("operange"))dataFromSub.setOperange((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("tilldepth"))dataFromSub.setTilldepth((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("cutter"))dataFromSub.setCutter((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("cutterconn"))dataFromSub.setCutterconn((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("drive"))dataFromSub.setDrive((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("transportation"))dataFromSub.setTransportation((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("gearbox"))dataFromSub.setGearbox((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("knife"))dataFromSub.setKnife((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("knifeMax"))dataFromSub.setKnifeMax((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("knifenum"))dataFromSub.setKnifenum((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("tooltype"))dataFromSub.setTooltype((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("depthlimit"))dataFromSub.setDepthlimit((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("suppress"))dataFromSub.setSuppress((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("power"))dataFromSub.setPower((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("rotate"))dataFromSub.setRotate((String)productSpecificationInfo.getDesignValue());
            return null;
        }).collect(Collectors.toList());
        ProductSpecificationExportVo productSpecificationExportVo = new ProductSpecificationExportVo();
        BeanUtils.copyProperties(dataFromSub,productSpecificationExportVo);
        productSpecificationExportVo.setPersonEnterprise(productSpecification.getPersonEnterprise());
        productSpecificationExportVo.setTimeEnter(productSpecification.getTimeEnter());

        JSONObject data = JSONObject.parseObject(JSONObject.toJSONString(productSpecificationExportVo));
        File tempFile = WordUtil.getWordFile("template/productspecification.docx", data, Configure.builder());
        String fileName = "产品规格表";
        String uploadDirectory = fileUploadUtil.getUploadFilePath("temp");
        String filePath = uploadDirectory + productSpecification.getProjectNumber() + fileName;
        String savePath = RequestUtils.getBasePath(request) + "upload/temp/" + productSpecification.getProjectNumber() +fileName;
        FileUtil.copy(tempFile, new File(filePath + ".docx"),true);
        PDFUtil.WordToPdf(tempFile, new File(filePath + ".pdf"));
        this.update(new LambdaUpdateWrapper<ProductSpecification>().set(ProductSpecification::getWordPath, savePath + ".docx").set(ProductSpecification::getPdfPath, savePath + ".pdf").eq(ProductSpecification::getId, id));
        return RequestUtils.getBasePath(request) + "upload/temp/" + productSpecification.getProjectNumber() + fileName + ".pdf";
    }

    public String getByIdproductInfoExportWordVo(Integer id) {
        DataFromSub dataFromSub = new DataFromSub();
        ProductSpecification productSpecification = this.getById(id);
        QueryWrapper<ProductSpecificationInfo> productSpecificationInfoQueryWrapper = new QueryWrapper<>();
        productSpecificationInfoQueryWrapper.eq("product_specification_id", id);
        List<ProductSpecificationInfo> list = productSpecificationInfoService.list(productSpecificationInfoQueryWrapper);
        list.stream().map(productSpecificationInfo -> {
            if (productSpecificationInfo.getCharacteristic().equals("model"))dataFromSub.setModel((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("construction"))dataFromSub.setConstruction((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("outline"))dataFromSub.setOutline((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("job"))dataFromSub.setJob((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("operange"))dataFromSub.setOperange((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("tilldepth"))dataFromSub.setTilldepth((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("cutter"))dataFromSub.setCutter((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("cutterconn"))dataFromSub.setCutterconn((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("drive"))dataFromSub.setDrive((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("transportation"))dataFromSub.setTransportation((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("gearbox"))dataFromSub.setGearbox((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("knife"))dataFromSub.setKnife((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("knifeMax"))dataFromSub.setKnifeMax((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("knifenum"))dataFromSub.setKnifenum((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("tooltype"))dataFromSub.setTooltype((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("depthlimit"))dataFromSub.setDepthlimit((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("suppress"))dataFromSub.setSuppress((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("power"))dataFromSub.setPower((String)productSpecificationInfo.getDesignValue());
            if(productSpecificationInfo.getCharacteristic().equals("rotate"))dataFromSub.setRotate((String)productSpecificationInfo.getDesignValue());
            return null;
        }).collect(Collectors.toList());
        ProductSpecificationExportVo productSpecificationExportVo = new ProductSpecificationExportVo();
        BeanUtils.copyProperties(dataFromSub,productSpecificationExportVo);
        productSpecificationExportVo.setPersonEnterprise(productSpecification.getPersonEnterprise());
        productSpecificationExportVo.setTimeEnter(productSpecification.getTimeEnter());

        JSONObject data = JSONObject.parseObject(JSONObject.toJSONString(productSpecificationExportVo));
        File tempFile = WordUtil.getWordFile("template/productspecification.docx", data, Configure.builder());
        String fileName = "产品规格表";
        String uploadDirectory = fileUploadUtil.getUploadFilePath("temp");
        String filePath = uploadDirectory + productSpecification.getProjectNumber() + fileName;
        String savePath = RequestUtils.getBasePath(request) + "upload/temp/" + productSpecification.getProjectNumber() +fileName;
        FileUtil.copy(tempFile, new File(filePath + ".docx"),true);
        PDFUtil.WordToPdf(tempFile, new File(filePath + ".pdf"));
        this.update(new LambdaUpdateWrapper<ProductSpecification>().set(ProductSpecification::getWordPath, savePath + ".docx").set(ProductSpecification::getPdfPath, savePath + ".pdf").eq(ProductSpecification::getId, id));
        return RequestUtils.getBasePath(request) + "upload/temp/" + productSpecification.getProjectNumber() + fileName + ".docx";
    }

    @Override
    public Object auditList(DataStagingParam param) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LambdaQueryWrapper<ProductSpecification> queryWrapper = new LambdaQueryWrapper<>();
        List<AdminDto> adminDto = AuditUtil.getAdminDto(authentication.getName());
        Set<Integer> roleSet = adminDto.stream().map(a -> StateEnum.getStateEnumByAuditRole(a.getRoleCode()).getState()).collect(Collectors.toSet());
        roleSet.remove(StateEnum.UN_SUBMIT.getState());
        queryWrapper.in(ProductSpecification::getStatus, roleSet);
        return page(new Page<>(param.getPageNo(), param.getPageSize()), queryWrapper);
    }

    @Override
    public R audit(AuditParam auditParam) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        List<AdminDto> adminDos = AuditUtil.getAdminDto(authentication.getName());
        if (CollectionUtil.isEmpty(adminDos)) return R.error("您没有审核权限！");
        ProductSpecification productSpecification = this.getById(auditParam.getId());
        int state = productSpecification.getStatus();
        if (!auditParam.isState()) {
            updateById(productSpecification.setStatus(StateEnum.APPROVAL_NOT_PASS.getState())
                    .setAuditOpinion(auditParam.getAuditOpinion())
                    .setAuditDate(DateUtil.date().toDateStr()));
            return R.ok();
        }
        StateEnum currentAuditState = AuditUtil.getStateText(TableEnums.SPECIFICATION.getTableName(), state);
        Integer nextAuditStateIndex = AuditUtil.getNextAuditState(TableEnums.SPECIFICATION.getTableName(), state, adminDos.stream().map(AdminDto::getRoleCode).toList());
        AdminDto adminDto = adminDos.stream().filter(a -> StrUtil.equals(a.getRoleCode(), currentAuditState.getAuditRole()))
                .findFirst().orElse(null);
        if (adminDto == null || nextAuditStateIndex == null) return R.error("您没有审核权限！");
        if (StrUtil.equals(adminDto.getRoleCode(), AuditRoleEnums.COMPANY_HEAD.getCode())) productSpecification.setPersonEnterprise(adminDto.getAdSignature());productSpecification.setTimeEnter(new SimpleDateFormat("yyyy-MM-dd HH:ss:mm").format(new Date()));
        productSpecification.setStatus(nextAuditStateIndex)
                .setAuditOpinion(auditParam.getAuditOpinion())
                .setAuditDate(DateUtil.date().toDateStr());
        updateById(productSpecification);
        return R.ok();
    }

    @Override
    public List<ProductSpecificationVos> getByProductSpecificationNum(String number) {
        MPJLambdaWrapper<ProductSpecification> productSpecificationVoLambdaQueryWrapper = new MPJLambdaWrapper<>();
        productSpecificationVoLambdaQueryWrapper
                .select(ProductSpecificationInfo::getCharacteristic,ProductSpecificationInfo::getDesignValue)
                .leftJoin(ProductSpecificationInfo.class, ProductSpecificationInfo::getProductSpecificationId, ProductSpecification::getId)
                .eq(ProductSpecification::getProjectNumber, number);
        List<ProductSpecificationVos> productSpecificationVos = productSpecificationMapper.selectJoinList(ProductSpecificationVos.class, productSpecificationVoLambdaQueryWrapper);
        return productSpecificationVos;
    }

    @Override
    public String viewPdf(Integer id) {
        String s = getByIdproductInfoExportVo(id);
        return s;
    }

    @Override
    public String viewWord(Integer id) {
        String s = getByIdproductInfoExportWordVo(id);
        return s;
    }
}